package com.my.lucky.util;

import com.my.lucky.model.Stock;

import java.util.ArrayList;
import java.util.List;

/**
 * KDJ技术指标计算类
 * K线: 当日RSV的M1日移动平均值
 * D线: K线的M2日移动平均值
 * J线: 3D - 2K
 */
public class KDJ {
    private final int rsvPeriod; // RSV计算周期，默认9
    private final int kPeriod;   // K值计算周期，默认3
    private final int dPeriod;   // D值计算周期，默认3

    public KDJ() {
        this(9, 3, 3);
    }

    public KDJ(int rsvPeriod, int kPeriod, int dPeriod) {
        this.rsvPeriod = rsvPeriod;
        this.kPeriod = kPeriod;
        this.dPeriod = dPeriod;
    }

    /**
     * 计算KDJ指标
     *
     * @param stocks 股票列表
     * @return KDJ结果，包含K线、D线和J线
     */
    public KDJResult calculateStock(List<Stock> stocks) {
        if (stocks == null || stocks.size() < rsvPeriod) {
            throw new IllegalArgumentException("股票数据不足");
        }

        List<Double> highPrices = stocks.stream()
                .map(Stock::getHigh)
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

        List<Double> lowPrices = stocks.stream()
                .map(Stock::getLow)
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

        List<Double> closePrices = stocks.stream()
                .map(Stock::getClose)
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

        return calculate(highPrices, lowPrices, closePrices);
    }

    /**
     * 计算KDJ指标
     *
     * @param highPrices  最高价序列
     * @param lowPrices   最低价序列
     * @param closePrices 收盘价序列
     * @return KDJ结果
     */
    public KDJResult calculate(List<Double> highPrices, List<Double> lowPrices, List<Double> closePrices) {
        if (highPrices == null || lowPrices == null || closePrices == null ||
                highPrices.size() != lowPrices.size() || highPrices.size() != closePrices.size() ||
                highPrices.size() < rsvPeriod) {
            throw new IllegalArgumentException("价格数据不足或数据长度不一致");
        }

        // 计算RSV
        List<Double> rsv = calculateRSV(highPrices, lowPrices, closePrices);

        // 计算K值（RSV的移动平均）
        List<Double> k = calculateSMA(rsv, kPeriod, 50.0); // K初始值为50

        // 计算D值（K的移动平均）
        List<Double> d = calculateSMA(k, dPeriod, 50.0); // D初始值为50

        // 计算J值 (3D - 2K)
        List<Double> j = new ArrayList<>();
        for (int i = 0; i < k.size(); i++) {
            double jValue = 3 * d.get(i) - 2 * k.get(i);
            j.add(jValue);
        }

        return new KDJResult(k, d, j);
    }

    /**
     * 计算RSV (Raw Stochastic Value)
     * RSV = (收盘价 - N日内最低价) / (N日内最高价 - N日内最低价) × 100
     */
    private List<Double> calculateRSV(List<Double> highPrices, List<Double> lowPrices, List<Double> closePrices) {
        List<Double> rsv = new ArrayList<>();

        // 前N-1天的RSV值设为0
        for (int i = 0; i < rsvPeriod - 1; i++) {
            rsv.add(0.0);
        }

        // 计算RSV
        for (int i = rsvPeriod - 1; i < closePrices.size(); i++) {
            double high = Double.MIN_VALUE;
            double low = Double.MAX_VALUE;

            // 计算N日内的最高价和最低价
            for (int j = i - rsvPeriod + 1; j <= i; j++) {
                high = Math.max(high, highPrices.get(j));
                low = Math.min(low, lowPrices.get(j));
            }

            double close = closePrices.get(i);
            double rsvValue = (high - low) < 0.000001 ? 100 : ((close - low) / (high - low)) * 100;
            rsv.add(rsvValue);
        }

        return rsv;
    }

    /**
     * 计算移动平均
     *
     * @param data         数据序列
     * @param period       周期
     * @param defaultValue 默认值
     */
    private List<Double> calculateSMA(List<Double> data, int period, double defaultValue) {
        List<Double> sma = new ArrayList<>();
        sma.add(defaultValue); // 第一个值使用默认值

        for (int i = 1; i < data.size(); i++) {
            double value = (sma.get(i - 1) * (period - 1) + data.get(i)) / period;
            sma.add(value);
        }

        return sma;
    }

    /**
     * KDJ计算结果类
     */
    public static class KDJResult {
        private final List<Double> k;  // K线
        private final List<Double> d;  // D线
        private final List<Double> j;  // J线

        public KDJResult(List<Double> k, List<Double> d, List<Double> j) {
            this.k = k;
            this.d = d;
            this.j = j;
        }

        public List<Double> getK() {
            return k;
        }

        public List<Double> getD() {
            return d;
        }

        public List<Double> getJ() {
            return j;
        }

        /**
         * 获取最新的K值
         */
        public double getLatestK() {
            return k.get(k.size() - 1);
        }

        /**
         * 获取最新的D值
         */
        public double getLatestD() {
            return d.get(d.size() - 1);
        }

        /**
         * 获取最新的J值
         */
        public double getLatestJ() {
            return j.get(j.size() - 1);
        }

        /**
         * 判断是否为超买信号（K、D值同时大于80）
         */
        public boolean isOverbought() {
            if (k.isEmpty() || d.isEmpty()) return false;
            return getLatestK() > 80 && getLatestD() > 80;
        }

        /**
         * 判断是否为超卖信号（K、D值同时小于20）
         */
        public boolean isOversold() {
            if (k.isEmpty() || d.isEmpty()) return false;
            return getLatestK() < 20 && getLatestD() < 20;
        }

        /**
         * 判断是否为金叉（K线从下向上穿过D线）
         */
        public boolean isGoldenCross() {
            if (k.size() < 2 || d.size() < 2) return false;
            int last = k.size() - 1;
            return k.get(last - 1) <= d.get(last - 1) && k.get(last) > d.get(last);
        }

        /**
         * 判断是否为死叉（K线从上向下穿过D线）
         */
        public boolean isDeathCross() {
            if (k.size() < 2 || d.size() < 2) return false;
            int last = k.size() - 1;
            return k.get(last - 1) >= d.get(last - 1) && k.get(last) < d.get(last);
        }
    }
} 